﻿using Anno.CronNET;
using Anno.RateLimit;
using System;
using System.Collections.Concurrent;
using System.Net;

namespace Microsoft.AspNetCore
{
    public class DefaultRateLimitStrategy : IRateLimitStrategy
    {
        private volatile ConcurrentDictionary<string, LimitInfo> _rateLimitPool = new ConcurrentDictionary<string, LimitInfo>();
        private readonly CronDaemon CronDaemon = new CronDaemon();
        /// <summary>
        /// true 代表不限制
        /// QPS 限制10 桶大小10
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public bool Request(HttpContext context)
        {
            bool notLimit = true;
            IPAddress ip = context.Connection.RemoteIpAddress.MapToIPv4();
            _rateLimitPool.TryGetValue(ip.ToString(), out LimitInfo limitInfo);
            if (limitInfo == null)
            {

                var limitingService = LimitingFactory.Build(TimeSpan.FromSeconds(1)
                         , LimitingType.LeakageBucket
                         , 5
                         , 5);
                limitInfo = new LimitInfo()
                {
                    Time = DateTime.Now,
                    limitingService = limitingService
                };
                _rateLimitPool.TryAdd(ip.ToString(), limitInfo);

            }
            if (limitInfo != null)
            {
                //limit.Request() ==true 代表不受限制
                limitInfo.Time = DateTime.Now;
                notLimit = limitInfo.limitingService.Request();
            }
            return notLimit;
        }
    }
    /// <summary>
    /// 限流 配置
    /// </summary>
    public class LimitCfg
    {
        /// <summary>
        /// 时间片段  1
        /// </summary>
        public uint timeSpan { get; set; } = 1;
        /// <summary>
        /// 单位 时间片段 内允许通过的请求个数  2
        /// </summary>
        public uint maxQPS { get; set; } = 2;
        /// <summary>
        /// 令牌桶大小  2
        /// </summary>
        public uint limitSize { get; set; } = 2;
    }

    class LimitInfo
    {
        public DateTime Time { get; set; } = DateTime.Now;
        public ILimitingService limitingService { get; set; }
    }
}
